package fstypes;

BEGIN {
	use Exporter   ();
	our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
	$VERSION     = 1.00;
	@ISA         = qw(Exporter);
	@EXPORT      = qw(&do_fsck &do_resize);
	%EXPORT_TAGS = ();
	@EXPORT_OK   = ();
}
our @EXPORT_OK;
my  @FS_TYPES=qw(vxfs ext3 ext4 jfs jfs2 xfs nfs ufs zfs);

sub do_fsck($$) {
my ($type,$dev)=@_;
my ($os,$bin,$cmd);

	if($type eq "nfs" || $type eq "zfs") {
		return(1,undef); # NFS/ZFS never need an fsck to mount!
	}
	local $SIG{CHLD}='DEFAULT';
	$os=lc($^O);
	$bin="/sbin/fsck" if -e "/sbin/fsck";
	$bin="/usr/sbin/fsck" if -e "/usr/sbin/fsck";
	if(! scalar(grep {$_ eq $type} @FS_TYPES)) {
		return(0,"File system type '$type' not supported.");
	}
	if(!defined($bin)) {
		return(0,"Unable to find fsck binary for fs type '$type'.");
	}
	if($os eq "linux") {
		$cmd="$bin -y -t $type $dev"
	} else {
		$cmd="$bin -y -F $type $dev"
	}
	if(defined($cmd)) {
		my $r=`$cmd 2>&1`;
		if($?>>8) {
			chomp $r;
			return(0,"Fsck using '$cmd' failed:\n$r");
		}
		return(1,undef);
	}
	return (0,"Specified OS/FS type not recognised.");
}

#########################################################################
# Resize a file system changing it from oldsize to newsize.		#
# Arguments expected are:						#
# type		- The file system type 					#
# dev		- The mounted device, such as /dev/drbd2		#
# mntpnt	- The file system mount point				#
# oldsize	- The old [current] size				#
# newsize	- The new size of the file system			#
#									#
# The return codes are:							#
# (0,undef)	- Resize completed successfully.			#
# (1,msg)	- New size is smaller than oldsize - size reduction	#
#		  is not supported by this file system.			#
# (2,errmsg)	- File system resize failed.				#
# (3,errmsg)	- File system type is not currently supported.		#
# (4,errmsg)	- Resizing is not supported as yet for this filesystem	#
#		  type.							#
#########################################################################

sub do_resize($$$$$) {
my ($type,$dev,$mntpnt,$oldsize,$newsize)=@_;
my $cmd;

	local $SIG{CHLD}='DEFAULT';
	if($oldsize == $newsize) {
		return(0,undef);
	}

	if(! scalar(grep {$_ eq $type} @FS_TYPES)) {
		return(3,"File system type '$type' not supported.");
	}
	$os=lc($^O);
	#################################################################
	# VxFS uses the mntpoint to resize against...			#
	#################################################################
	my $bin="/sbin/fsadm" if -e "/sbin/fsadm";
	$bin="/usr/sbin/fsadm" if -e "/usr/sbin/fsadm";
	if($^O eq "aix") {
		my $blocks=$newsize*2;
		$bin="/usr/sbin/chfs -a size=$newsize $mntpnt";
	}

	#################################################################
	# For zfs all resizing is at the lvm level, so do nothing	#
	# at the 'file system' level.					#
	#################################################################
	if($type eq "zfs") {
		return (0,undef);
	}

	if($type eq "vxfs") {
		$cmd="$bin -F vxfs -b $newsize $mntpnt";
	}
	if($newsize < $oldsize) {
		if($^O ne "aix" || $type ne "vxfs") {
			return(1,"Size of '$newsize' is smaller than then existing size of '$oldsize'. File system reduction is not currently supported for file systems of type '$type'.");
		}
	}
	if($^O ne "aix" && $type eq "jfs") {
		$cmd="PATH=\$PATH:/sbin:/bin:/usr/sbin; mount -o remount,resize=$newsize $mntpnt";
	}
	if($type eq "reiserfs") {
		my $s=1024*$newsize; # newsize is in Kb - need bytes for reiserfs
		$cmd="PATH=\$PATH:/sbin:/bin:/usr/sbin; resize_reiserfs -s $s $dev";
	}
	if($type eq "ext3" || $type eq "ext4") {
		# We might have ext2online or resize2fs depending on Linux varient ...
		my @P=("/sbin","/bin","/usr/bin","/usr/sbin");
		$cmd=undef;
		for my $cc ("resize2fs","ext2online") {
			for my $cp (@P) {
				if(-x "$cp/$cc") {
					$cmd="$cp/$cc $dev ${newsize}K"; last;
				}
			}
			last if defined($cmd);
		}
	}
	if($type eq "xfs") {
		$cmd="PATH=\$PATH:/sbin:/bin:/usr/sbin; xfs_growfs $mntpnt";
	}
	if($type eq "ufs") {
		# We are given the block dev, but Solaris wants raw dev...
		$dev =~ s!/dsk/!/rdsk/!g;
		$cmd="PATH=\$PATH:/sbin:/bin:/usr/sbin; growfs -M $mntpnt $dev";
	}

	#################################################################
	# If we have a command then attempt to execute it.		#
	#################################################################

	if(defined($cmd)) {
		my $r=`$cmd 2>&1`;
		if($?>>8) {
			chomp $r;
			return(2,"Resize using '$cmd' failed:\n$r");
		}
		return(0,undef);
	}

	return(4,"Resizing on file systems of type '$type' is not yet supported.");
}

1;

